#include <iostream>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/select.h>
#include <signal.h>
#include "../../macro.h"

using std::cout;
using std::cerr;
using std::endl;

constexpr static int BUF_SIZE = 1024;

struct Protocol{
    int flag;
    char buf[BUF_SIZE];
};

static int wfd, rfd;

void read(int fd, struct Protocol *proto)
{
    int ret = ::read(fd, proto->buf, BUF_SIZE);
    ERR_CHECK(ret, -1, "read")

    proto->flag = 1; 
    /* if(ret == 0){
        cerr << "读端断开连接" << endl;
    }else{
        proto->flag = 1; 
    } */
}

Protocol *init_shm()
{
    int shmid = shmget(1000, sizeof(struct Protocol), IPC_CREAT | 0600);
    ERR_CHECK(shmid, -1, "shmget")

    struct Protocol *proto = (struct Protocol *)shmat(shmid, NULL, 0);
    ERR_CHECK(proto, (struct Protocol *)-1, "shmat")

    bzero(proto, sizeof(struct Protocol));
    return proto;
}

void run()
{
    // 创建 a - b的读写管道
    wfd = open("./1.pipe", O_CREAT | O_WRONLY);
    ERR_CHECK(wfd, -1, "open 1")
    rfd = open("./2.pipe", O_CREAT | O_RDONLY);
    ERR_CHECK(rfd, -1, "open 2")

    // 创建 a - a1 的共享内存 
    struct Protocol *protol = init_shm();

    fd_set rds;
    while(1){
        FD_ZERO(&rds);
        FD_SET(STDIN_FILENO, &rds);
        FD_SET(rfd, &rds);

        int ret = select(rfd + 1, &rds, nullptr, nullptr, 0);
        ERR_CHECK(ret, -1, "select")

        if(FD_ISSET(STDIN_FILENO, &rds)){
            read(STDIN_FILENO, protol);
            ret = ::write(wfd, protol->buf, strlen(protol->buf));
            ERR_CHECK(ret, -1, "write")
        }

        if(FD_ISSET(rfd, &rds)){
            read(rfd, protol);
        }
    }
}

// SIGPIPE 写入无人读取的管道
void handle_pipe_close(int signum, siginfo_t *info, void *p)
{
    close(wfd);
    close(rfd);

    int shmid = shmget(1000, sizeof(struct Protocol), IPC_CREAT | 0600);
    shmctl(shmid, IPC_RMID, nullptr);
}

// 注册 SIGPIPE 、SIGINT、SIGQUIT 信号
void register_signal()
{
    struct sigaction act{};
    act.sa_sigaction = handle_pipe_close;
    act.sa_flags = SA_SIGINFO;
    // 当某一个读端关闭时，另外一端应将所有资源释放，并且不能被打断
    // int ret = sigfillset(&(act.sa_mask));
    // ERR_CHECK(ret, -1, "sigfillset")

    sigaction(SIGPIPE, &act, nullptr);
}

int main(int args, char *argv[])
{
    register_signal();
    run();
    return 0;
}